﻿#ifndef MESSAGELOGGER_H
#define MESSAGELOGGER_H

/** @description 用于Qt 项目的一个简单的日志库，将日志存入日志文件（文本文件）中。
 *   下一步准备加入对数据库的支持。将日志存入一个 QSLite 数据库中。
 *   下面是典型的用法示例：
 *   第一个 FileLogger 将日志输出到 stderr 上。
 *   第二个 FileLogger 将日志输出到文件。
 *   建议将这段代码放到 main 函数的开头处，但是要在 QCoreApplication 或 QApplication 之后。
 *     LoggerController logger;
 *     logger.attach(new FileLogger("stderr",
 *                               FileLogger::E_DEBUG |
 *                               FileLogger::E_INFO |
 *                               FileLogger::E_WARNING |
 *                               FileLogger::E_CRITICAL |
 *                               FileLogger::E_FATAL));
 *  logger.attach(new FileLogger("d:/log2.txt"));
 *  logger.startLogging();
*/

#include <QtCore/QString>
#include <QtCore/QFile>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QDebug>
#include <QtCore/QMessageLogContext>

class FileLogger
{
public:
    enum LEVEL{E_DEBUG = 1, E_INFO = 2, E_WARNING = 4, E_CRITICAL = 8, E_FATAL = 16};
    FileLogger(QString name, LEVEL level);
    FileLogger(QString name = "stderr", bool debug = false, bool info = true, bool warning = true, bool critical= true, bool fatal = true);
    virtual ~FileLogger();
    /**
     * @brief setFileName 设置日志存储的文件名
     * @param name 日志存储的文件名，如果为 "stderr" 则输出到 stderr
     * @return
     */
    bool setFileName(QString name = "stderr");
    /**
     * @brief setLogLevel 设置哪些级别的信息要输出到文件
     * @param level 可以为 E_DEBUG、E_INFO、E_WARNING、E_CRITICAL、E_FATAL 或者这些项的组合（bit or）
     *              没有设置的 level 则不输出日志
     */
    void setLogLevel(LEVEL level);
    /**
     * @brief setLogLevel 设置哪些级别的信息要输出到文件
     * @param debug  true 表示 qDebug 信息输出到日志
     * @param info   true 表示 qInfo 信息输出到日志
     * @param warning  true 表示 qWarning 信息输出到日志
     * @param critical true 表示 qCritical 信息输出到日志
     * @param fatal    true 表示 qFatal 信息输出到日志
     */
    void setLogLevel(bool debug = false, bool info = true, bool warning = true, bool critical= true, bool fatal = true);
    virtual void writeLog(QtMsgType type, const QMessageLogContext &context, const QString &msg);
private:
    QString messageType(QtMsgType type);
    FileLogger(FileLogger &f) {Q_UNUSED(f);} // 不能被拷贝
    FileLogger& operator=( FileLogger &f) {Q_UNUSED(f);} // 不能被拷贝
private:
    QFile m_file;
    QMap<QtMsgType, bool> m_level;
    bool m_where;
};

class LoggerController
{
public:
    LoggerController(){}
    ~LoggerController();
    /**
     * @brief startLogging 启动日志系统，在这之后所有的调试信息发送到对应的 FileLogger
     */
    void startLogging();
    /**
     * @brief attach 在日志系统中注册一个新的 FileLogger
     * @param m_currentLogger
     */
    void attach(FileLogger *m_currentLogger);
    void detach(FileLogger *m_currentLogger);
private:
    static void writeLog(QtMsgType type, const QMessageLogContext &context, const QString &msg);
    static LoggerController * m_currentLogger;
    QList<FileLogger *> m_list;
};

#endif // MESSAGELOGGER_H
